package cz.data.common.elastic;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import cz.data.common.support.db.DbProperty;
import cz.data.common.support.db.DbType;
import cz.data.common.support.db.core.DbColumn;
import cz.data.common.support.db.manage.Condition;
import cz.data.common.utils.SecurityUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.message.BasicHeader;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.RestClients;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class ElasticSearchUtils {

    public static RestHighLevelClient createClient(DbProperty property) {
        String url = DbType.ELASTICSEARCH.getUrl();
        url = url.replace("${host}", property.getHost())
                .replace("${port}", String.valueOf(property.getPort()));
        ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                .connectedTo(url)
                .withBasicAuth(property.getUsername(), property.getPassword())
                .build();
        return RestClients.create(clientConfiguration).rest();
    }

    //todo 此客户端依赖的jakarta.json-api包名为jakarta前缀,spring其它模块旧版依赖的jakarta.json-api包名为javax前缀
    public static ElasticsearchClient createElasticsearchClient(DbProperty property) {
        String serverUrl = DbType.ELASTICSEARCH.getUrl();
        serverUrl = serverUrl.replace("${host}", property.getHost())
                .replace("${port}", String.valueOf(property.getPort()));
        String basicToken = SecurityUtil.createBasicToken(property.getUsername(), property.getPassword());
        RestClient restClient = RestClient
                .builder(HttpHost.create(serverUrl))
                .setDefaultHeaders(new Header[]{
                        new BasicHeader("Authorization", basicToken)
                }).build();
        ElasticsearchTransport transport = new RestClientTransport(
                restClient, new JacksonJsonpMapper());
        return new ElasticsearchClient(transport);
    }

    public static List<QueryBuilder> parseQueryBuilds(List<DbColumn> columns, List<Condition> conditions) {
        List<QueryBuilder> queryBuilders = new ArrayList<>();
        for (DbColumn column : columns) {
            for (Condition condition : conditions) {
                if (StringUtils.equals(column.getColName(), condition.getColumn())) {
                    if (StringUtils.isBlank(condition.getQueryType())) {
                        continue;
                    }
                    switch (condition.getQueryType()) {
                        case "eq":
                            if (isNotBlank(condition.getValue())) {
                                queryBuilders.add(QueryBuilders.termQuery(condition.getColumn(), condition.getValue()));
                            }
                            break;
                        case "ne":
                            if (isNotBlank(condition.getValue())) {
                                queryBuilders.add(
                                        QueryBuilders.boolQuery().mustNot(
                                                QueryBuilders.termQuery(condition.getColumn(), condition.getValue()))
                                );
                            }
                            break;
                        case "like":
                            if (isNotBlank(condition.getValue())) {
                                queryBuilders.add(
                                        QueryBuilders.wildcardQuery(condition.getColumn(), condition.getValue().toString())
                                );
                            }
                            break;
                        case "gt":
                            if (isNotBlank(condition.getValue())) {
                                queryBuilders.add(
                                        QueryBuilders.rangeQuery(condition.getColumn())
                                                .gt(condition.getValue())
                                );
                            }
                            break;
                        case "ge":
                            if (isNotBlank(condition.getValue())) {
                                queryBuilders.add(
                                        QueryBuilders.rangeQuery(condition.getColumn())
                                                .gte(condition.getValue())
                                );
                            }
                            break;
                        case "lt":
                            if (isNotBlank(condition.getValue())) {
                                queryBuilders.add(
                                        QueryBuilders.rangeQuery(condition.getColumn())
                                                .lt(condition.getValue())
                                );
                            }
                            break;
                        case "le":
                            if (isNotBlank(condition.getValue())) {
                                queryBuilders.add(
                                        QueryBuilders.rangeQuery(condition.getColumn())
                                                .lte(condition.getValue())
                                );
                            }
                            break;
                        case "between":
                            if (isNotBlank(condition.getLeftValue()) && isNotBlank(condition.getRightValue())) {
                                queryBuilders.add(
                                        QueryBuilders.rangeQuery(condition.getColumn())
                                                .gte(condition.getLeftValue())
                                                .lte(condition.getRightValue())
                                );
                            }
                            break;
                        default:
                            break;
                    }
                    break;
                }
            }
        }
        return queryBuilders;
    }

    public static boolean isNotBlank(Object value) {
        return Objects.nonNull(value) && StringUtils.isNotBlank(value.toString());
    }
}
